import common from "shared/component/common/common";
import { ContainerService } from "shared/component/container/ContainerService";
import EventBinder from "shared/component/event/EventBinder";
import Log4R from "shared/component/log/Log4R";
import { setTimeOut } from "shared/component/time/SetTime";
import { AirState, CharacterState, CrouchState } from "shared/enums/CharacterState";
import { triggerStateConfig } from "../config/triggerStateConfig";
import { ColiGroup } from "shared/enums/ColiGroup";
import stateConfig from "../config/stateConfig";
import { stickDirection, stickTools } from "shared/component/common/stickTools";
import FrameManager from "shared/component/time/FrameManager";

const loginfo = Log4R.getLog('info');

/** 复杂状态 */
export class CharacterStateServiceImpl extends ContainerService<Ctn.CharacterStateService, Ctn.CharacterStateEntity> implements Ctn.CharacterStateService {
    /**
     * 机关事件导致状态改变
     * @param trigger 
     * @param toucher 
     * @returns 是否成功
     */
    changeStateByTrigger(trigger: clazz.TriggerBase, toucher: BasePart) {
        let success: boolean | undefined = false
        const triggerState = triggerStateConfig[trigger.clazz];
        if (triggerState?.state) {
            success = triggerState.test(toucher);
            if (!success) return false
            const humanModel = toucher.FindFirstAncestorOfClass('Model') as Ctn.character.HumanModel;
            if (!humanModel) return
            success = this.computeState({
                humanModel,
                state: triggerState.state
            })
        }
        return success;
    }
    protected serverCalls: (keyof this)[] = ['getStateConfig'];
    protected serviceName: keyof Ctn.Services = "characterStateService";
    // private characterMap = new InstanceMap<Ctn.character.HumanModel, Ctn.CharacterState.MutiHumanStates>()

    /** 获取state */
    private getState(character: Model) {
        const characterEntity = this.getCharacter(character);
        return characterEntity?.humanStates

    }
    /** 添加角色 */
    public addCharacter(characterEntity: Ctn.character.CharacterEntity) {

        characterEntity.character?.Humanoid.SetStateEnabled(Enum.HumanoidStateType.Climbing, false);
        const state: Ctn.CharacterState.MutiHumanStates = {
            speed: 0,
            airStates: AirState.Ground,
            actStates: CharacterState.Standing,
            crouchStates: CrouchState.Stand,
            ctrlDegree: 0
        };
        characterEntity.humanStates = state
        if (characterEntity.character)
            this.listener(characterEntity.character)
    }

    /**
     * 角色状态变更
     */
    private stateChangeEventBinder = new EventBinder<(p: Ctn.CharacterStateEntity, character: Ctn.character.HumanModel) => void>()
    /**
     * 状态改变
     */
    onStateChange = this.stateChangeEventBinder.bind()
    /** 最低跑步速度 */
    private speedThreshold = 2
    /** 状态数据 */
    private stateInfo: {
        [key: number]: Ctn.CharacterState.State
    } = {}
    /**
     * 强制修改状态,不触发状态修改事件
     */
    public ForceChangeCurrentStae(computeEntity: Ctn.CharacterState.ComputeEntity) {
        const humanModel = computeEntity.humanModel;
        const state = computeEntity.state;
        /** 当前状态 */
        const currentState = this.getState(humanModel);
        if (!currentState) return
        currentState.actStates = computeEntity.state
    }
    /**
     * 根据环境计算出一个状态
     * @param humanModel 
     * @returns 
     */
    public autoState(humanModel: Ctn.character.HumanModel) {
        /** 当前状态 */
        const currentState = this.getState(humanModel);
        if (!currentState) return
        if (currentState.airStates === AirState.Climbing) {
            this.computeState({
                state: CharacterState.Climbing,
                humanModel,
                speed: 0
            })
        } else if (currentState.airStates === AirState.Air) {
            this.computeState({
                state: CharacterState.FreeFalling,
                humanModel
            })
        } else if (currentState.speed > this.speedThreshold) {
            this.computeState({
                state: CharacterState.Running,
                humanModel
            })
        } else {
            if (currentState.crouchStates === CrouchState.Crouch) {
                this.computeState({
                    state: CharacterState.Crouch,
                    humanModel
                })
            } else {
                this.computeState({
                    state: CharacterState.Standing,
                    humanModel
                })
            }

        }
        // loginfo?.info("currentState.actStates:", currentState.actStates)
    }
    /** 计算状态 */
    public computeState(computeEntity: Ctn.CharacterState.ComputeEntity) {
        const humanModel = computeEntity.humanModel;
        const state = computeEntity.state;
        /** 当前状态 */
        const currentState = this.getState(humanModel);
        if (!currentState) {
            // loginfo?.info('!currentState')
            return
        }
        /** 之前的状态 */
        const finallStatesBefore = currentState.actStates;
        /** 目标状态 */
        const stateInfoTarget = computeEntity.stateInfo || this.stateInfo[state];
        if (!stateInfoTarget) {
            // loginfo?.info('!stateInfoTarget', computeEntity.stateInfo, this.stateInfo, state)
            return
        }
        /** 上一个状态 */
        const stateInfoBefore = currentState.currentState

        /** 设置环境 */
        const setAirStates = stateInfoTarget.setAirStates;

        if (setAirStates)
            currentState.airStates = setAirStates

        // /** 设置下蹲状态 */
        // const setCrouchStates = stateInfoTarget.setCrouchStates;
        // if (setCrouchStates) {
        //     currentState.crouchStates = setCrouchStates
        // }
        if (stateInfoTarget.forbiddenFrom?.find(c => c === finallStatesBefore)) {
            // loginfo?.info('禁止从此状态改变:', stateInfoTarget, finallStatesBefore)
            return
        }


        if (state === CharacterState.Skilling || finallStatesBefore !== state || stateInfoTarget.speedEnable) {//状态改变时触发事件
            currentState.currentState = stateInfoTarget
            currentState.actStates = state;

            /* 状态结束 自动状态变换 */
            if (stateInfoTarget.life) {
                /** 状态存在生命 */
                const life = stateInfoTarget.life;
                if (currentState.stateTimer) {
                    currentState.stateTimer.Disconnect()
                }
                currentState.stateTimer = setTimeOut(life.duration, () => {
                    const primaryPart = humanModel.PrimaryPart;
                    if (!primaryPart) return
                    if (currentState.currentState === stateInfoTarget) {//判断还是以前那个状态
                        const auto = life.autoTransfrom?.find(auto => {
                            if (auto.fall) {
                                loginfo?.info("primaryPart.AssemblyLinearVelocity", primaryPart.AssemblyLinearVelocity)
                            }
                            const result = (auto.fall && primaryPart.AssemblyLinearVelocity.Y < 0)
                                || auto.airStates === currentState.airStates
                            return result

                        }
                        )
                        if (auto) {
                            // loginfo?.info('state auto transform', auto.targetStates)
                            currentState.actStates = CharacterState.none
                            this.computeState({
                                state: auto.targetStates, humanModel
                            })
                        } else {
                            currentState.actStates = CharacterState.none
                            this.autoState(humanModel)
                        }
                    }
                })

            }
            // 通知状态改变事件
            // loginfo?.info("stateChange:", CharacterState[finallStatesBefore], CharacterState[state], stateInfoBefore, stateInfoBefore?.transform?.[state]?.transitionTime)
            this.stateChangeEventBinder.callBack({
                speed: computeEntity.speed,
                anim: computeEntity.anim,
                state: currentState,
                transitionTime: stateInfoBefore?.transform?.[state]?.transitionTime
            }, humanModel);
        }
        return true
    }
    /**
     * 设置移动控制，是经过修正后的移动控制
     * @param humanModel 
     * @param ctrl 
     */
    public setMoveControl(humanModel: Ctn.character.HumanModel, ctrl: Vector3) {
        const state = this.getState(humanModel)
        if (state)
            state.ctrl = ctrl;
    }
    /**
     * 设置角度控制，是遥感的2d角度
     * @param humanModel 
     * @param degree 
     */
    public setControlDegree(humanModel: Ctn.character.HumanModel, degree: number) {
        const state = this.getState(humanModel)
        if (state) {
            state.ctrlDegree = degree;
            // loginfo?.info('state.ctrlDegree', state.ctrlDegree)
            let needCrouch = false
            if (stickTools.getDirection(degree) === stickDirection.down) {
                needCrouch = true
                state.crouchStates = CrouchState.Crouch
            } else {
                state.crouchStates = CrouchState.Stand
            }
            if (state.actStates === CharacterState.Standing && needCrouch) {
                // loginfo?.info('needCrouch')
                this.computeState({
                    state: CharacterState.Crouch,
                    humanModel
                })
            } else if (state.actStates === CharacterState.Crouch && !needCrouch) {
                this.computeState({
                    state: CharacterState.Standing,
                    humanModel
                })
            }

        }
    }
    /** 玩家接触钉固物体表 */
    private playerTouchMap = new Map<Instance, Disconnecter<number>>()
    /** 监听 humanModel*/
    listener(humanModel: Ctn.character.HumanModel) {
        // loginfo?.info('监听角色：', humanModel)
        const characterEntity = this.getCharacter(humanModel);
        humanModel.WaitForChild('Humanoid')
        const state = this.getState(humanModel)
        let humanoid = humanModel.FindFirstChild('Humanoid') as Humanoid
        while (!humanoid) {
            common.waitForFirst(humanModel.ChildAdded, humanModel.AncestryChanged)
            humanoid = humanModel.FindFirstChild('Humanoid') as Humanoid
        }
        // (humanModel.Humanoid.Changed as RBXScriptSignal).Connect((a, b, c) => {
        //     if ((a as string) === "FloorMaterial") {
        //         // loginfo?.info('FloorMaterial', humanModel.Humanoid.FloorMaterial)
        //         if (humanModel.Humanoid.FloorMaterial === Enum.Material.Air) {
        //             humanModel.HumanoidRootPart.CollisionGroup = ColiGroup.characterJump;

        //         } else {
        //             humanModel.HumanoidRootPart.CollisionGroup = ColiGroup.character;
        //         }
        //     }

        // })
        // humanModel.LowerTorso.Touched.Connect(c => {
        //     if (c.CanCollide) {
        //         humanModel.HumanoidRootPart.CollisionGroup = ColiGroup.character;
        //     }
        // })
        humanModel.Humanoid.StateChanged.Connect((oldValue, newValue) => {
            // if (newValue === Enum.HumanoidStateType.Climbing)
            // loginfo?.info('StateChanged', oldValue, newValue)
            switch (newValue) {
                case Enum.HumanoidStateType.Jumping:
                    this.computeState({
                        state: CharacterState.Jumping,
                        humanModel
                    })
                    break;
            }
        })
        humanModel.Humanoid.Running.Connect(speed => {
            // loginfo?.info('Running', speed, state?.airStates && AirState[state?.airStates])

            if (state) {
                state.speed = speed;

                if (state.ctrl && state.ctrl.Magnitude > 0 && speed > this.speedThreshold && humanModel.Humanoid.WalkSpeed > 0) {
                    if (state?.airStates === AirState.Air) return
                    this.computeState({
                        state: CharacterState.Running,
                        humanModel
                    })
                } else {
                    if (state.crouchStates === CrouchState.Crouch) {
                        this.computeState({
                            state: CharacterState.Crouch,
                            humanModel
                        })
                    } else {
                        this.computeState({
                            state: CharacterState.Standing,
                            humanModel
                        })
                    }


                }
            }

        })
        humanModel.Humanoid.StateChanged.Connect(HumanoidStateType => {
            if (!state || !characterEntity) return
            // loginfo?.info('Running', speed, state?.airStates && AirState[state?.airStates])
            switch (HumanoidStateType) {
                case Enum.HumanoidStateType.Landed:
                    characterEntity.jumpTimes = 0
                    if (state.ctrl && state.ctrl.Magnitude > 0 && state.speed > this.speedThreshold && humanModel.Humanoid.WalkSpeed > 0) {
                        this.computeState({
                            state: CharacterState.Running,
                            humanModel
                        })
                    } else {
                        if (state.crouchStates === CrouchState.Crouch) {
                            this.computeState({
                                state: CharacterState.Crouch,
                                humanModel
                            })
                        } else {
                            this.computeState({
                                state: CharacterState.Standing,
                                humanModel
                            })
                        }
                    }
                    break;
            }


        })
        humanModel.Humanoid.FreeFalling.Connect(active => {
            if (active)
                this.computeState({
                    state: CharacterState.FreeFalling,
                    humanModel
                })
        })
        humanModel.Humanoid.Climbing.Connect(speed => {
            // loginfo?.info('Climbing', speed)
            this.computeState({
                speed,
                state: CharacterState.Climbing,
                humanModel
            })
        })
        // if (characterEntity?.player) {
        //     const humanoidRootPart = characterEntity.character?.HumanoidRootPart;
        //     humanoidRootPart?.TouchEnded.Connect(c => {
        //         if (this.playerTouchMap.has(c)) {
        //             this.playerTouchMap.get(c)?.Disconnect();
        //             this.playerTouchMap.delete(c)
        //         }
        //     })
        //     humanoidRootPart?.Touched.Connect(c => {
        //         if (!c.Anchored) return
        //         if (this.playerTouchMap.has(c)) return
        //         const connector = FrameManager.connect(() => {
        //             if (math.abs(humanoidRootPart.AssemblyLinearVelocity.Y) < 0.001) return
        //             /** 玩家高出物体y轴距离 */
        //             const y = humanoidRootPart.Position.Y - c.Position.Y - c.Size.Y / 2
        //             loginfo?.info(c, y)
        //             if (math.abs(y) <= 0.1) {
        //                 /** x轴距离 */
        //                 const distanceX = humanoidRootPart.Position.X - c.Position.X;
        //                 if (math.abs(math.abs(distanceX) - c.Size.Y / 2) < 0.01) {
        //                     loginfo?.info(c, distanceX)
        //                     connector?.Disconnect();
        //                     this.playerTouchMap.delete(c)
        //                 }
        //             }
        //         })
        //         this.playerTouchMap.set(c, connector)

        //     })
        // }

        return state
    }
    public getStateConfig(entity: Ctn.CharacterStateEntity) {
        return this.invoke('getStateConfig', entity)
    }
    public run(): void {
        if (this.runInLocal()) {
            this.stateInfo = stateConfig
        }
        // loginfo?.info('this.stateInfo', this.stateInfo)
    }
    /**
     * 动作触发状态
     * @param act 
     * @param humanModel 
     */
    public act(act: Ctn.character.ActEntity, humanModel: Ctn.character.HumanModel) {
        const state = this.getState(humanModel);
        // 下跳动作判断
        switch (act.act) {
            case 'jump':
                if (state?.actStates === CharacterState.Crouch) {
                    this.computeState({
                        state: CharacterState.DownJumping,
                        humanModel
                    })
                }
                break;
        }

    }
    public init(): void {
        // FrameManager.connect(() => {
        //     this.getInstanceMap().forEach(c => {
        //         loginfo?.info(c.character?.HumanoidRootPart)
        //     })
        // })
    }
}